package com.cskaoyan.wordmemorize.aspect;

import com.cskaoyan.wordmemorize.auth.StpKit;
import com.cskaoyan.wordmemorize.common.annotation.OperateLog;
import com.cskaoyan.wordmemorize.dao.entity.OperateLogDO;
import com.cskaoyan.wordmemorize.service.AdminLogService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.time.LocalDateTime;

/**
 * 操作日志切面类
 */
@Aspect
@Component
@Slf4j
public class OperateLogAspect {

    @Autowired
    private AdminLogService adminLogService;

    @Autowired
    private ObjectMapper objectMapper;

    /**
     * 定义切点，拦截所有带有 OperateLog 注解的方法
     */
    @Pointcut("@annotation(com.cskaoyan.wordmemorize.common.annotation.OperateLog)")
    public void operateLogPointcut() {
    }

    /**
     * 环绕通知，记录操作日志
     *
     * @param joinPoint 连接点
     * @return 方法执行结果
     */
    @Around("operateLogPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取当前登录用户ID
        Long employeeId = null;

        try {
            // 使用StpKit.ADMIN而不是StpUtil，因为这是后台操作日志
            if (StpKit.ADMIN.isLogin()) {
                employeeId = Long.valueOf(StpKit.ADMIN.getLoginIdAsString());
                log.info("获取到用户ID: {}", employeeId);
            } else {
                log.warn("当前没有登录用户");
            }
        } catch (Exception e) {
            log.warn("获取当前登录用户ID失败: {}", e.getMessage());
        }

        // 获取方法签名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();

        // 获取方法上的 OperateLog 注解
        OperateLog operateLog = method.getAnnotation(OperateLog.class);

        // 创建操作日志对象
        OperateLogDO operateLogDO = new OperateLogDO();
        operateLogDO.setEmployeeId(employeeId);
        operateLogDO.setDataType(operateLog.dateType());
        operateLogDO.setOperateType(operateLog.operateType());
        operateLogDO.setCreateTime(Timestamp.valueOf(LocalDateTime.now()));
        operateLogDO.setStatus(1); // 默认成功

        // 执行原方法
        Object result = null;
        try {
            result = joinPoint.proceed();

            // 根据操作类型处理日志数据
            processLogData(operateLog.operateType(), joinPoint.getArgs(), result, operateLogDO);

            // 保存操作日志
            adminLogService.saveOperateLog(operateLogDO);
        } catch (Exception e) {
            // 操作失败，设置状态为失败
            operateLogDO.setStatus(0);
            adminLogService.saveOperateLog(operateLogDO);
            throw e;
        }

        return result;
    }

    /**
     * 根据操作类型处理日志数据
     *
     * @param operateType  操作类型
     * @param args         方法参数
     * @param result       方法返回值
     * @param operateLogDO 操作日志对象
     */
    private void processLogData(int operateType, Object[] args, Object result, OperateLogDO operateLogDO) {
        try {
            // 根据操作类型处理日志数据
            switch (operateType) {
                case 1: // 新增
                case 2: // 修改
                case 5: // 修改状态
                    // 对于新增、修改和修改状态操作，使用请求参数作为日志数据
                    if (args != null && args.length > 0) {
                        operateLogDO.setData(objectMapper.writeValueAsString(args[0]));
                    }
                    break;


                case 3: // 单个删除
                case 4: // 批量删除
                case 6: // excel导入
                    // 对于删除和excel导入操作，使用返回值作为日志数据
                    if (result != null) {
                        operateLogDO.setData(objectMapper.writeValueAsString(result));
                    }
                    break;
                default:
                    break;
            }
        } catch (JsonProcessingException e) {
            log.error("处理操作日志数据失败", e);
        }
    }
}
